﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls;
using System.Reflection;
using System.Web.UI;
using System.Web;

namespace Mpu.NHibernateDataModelProvider
{
    public class NHibernateLinqDataSource : LinqDataSource
    {
        private NHibernateLinqDataSourceView view;

        public NHibernateLinqDataSource()
        {
            FieldInfo fi = typeof(LinqDataSource).GetField("_view", BindingFlags.Instance | BindingFlags.NonPublic);
            this.view = new NHibernateLinqDataSourceView(this, this.Context);

            fi.SetValue(this, view);
            if ((this.view != null) && base.IsTrackingViewState)
            {
                ((IStateManager)this.view).TrackViewState();
            }
        }

        private class NHibernateLinqDataSourceView : LinqDataSourceView
        {
            public NHibernateLinqDataSourceView(NHibernateLinqDataSource owner, HttpContext httpContext)
                : base(owner, "DefaultView", httpContext)
            {

            }

            protected override MemberInfo GetTableMemberInfo(Type contextType)
            {
                if (typeof(GenericNHibernateContext).IsAssignableFrom(contextType))
                    return new StubFieldInfo(this.TableName);
                else
                {
                    throw new Exception("pmalyavkin!!");
                    //return base.GetTableMemberInfo(contextType);
                }
            }

            protected override void ValidateContextType(Type contextType, bool selecting)
            {
                //base.ValidateContextType(contextType, selecting);
            }

            protected override void ValidateTableType(Type tableType, bool selecting)
            {
                //base.ValidateTableType(tableType, selecting);
            }

            protected override void InsertDataObject(object dataContext, object table, object newDataObject)
            {
                //base.InsertDataObject(dataContext, table, newDataObject);

                var context = (GenericNHibernateContext)dataContext;

                using (var transaction = context.Session.BeginTransaction())
                {
                    context.Session.Save(newDataObject);
                    transaction.Commit();
                }
            }

            protected override void UpdateDataObject(object dataContext, object table, object oldDataObject, object newDataObject)
            {
#warning pmalyavkin (Update of Primary Key is not supported)
                //base.UpdateDataObject(dataContext, table, oldDataObject, newDataObject);
                var context = (GenericNHibernateContext)dataContext;

                using (var transaction = context.Session.BeginTransaction())
                {
                    context.Session.SaveOrUpdate(newDataObject);
                    transaction.Commit();
                }
            }

            protected override void DeleteDataObject(object dataContext, object table, object oldDataObject)
            {
                //base.DeleteDataObject(dataContext, table, oldDataObject);

                var context = (GenericNHibernateContext)dataContext;

                using (var transaction = context.Session.BeginTransaction())
                {
                    context.Session.Delete(oldDataObject);
                    transaction.Commit();
                }
            }

            class StubFieldInfo : FieldInfo
            {
                private string name;

                public StubFieldInfo(string name)
                {
                    this.name = name;
                }

                public override object GetValue(object obj)
                {
                    return ((GenericNHibernateContext)obj).GetTable(name);
                }

                #region Not implemented (not needed)

                public override FieldAttributes Attributes
                {
                    get { throw new NotImplementedException(); }
                }

                public override RuntimeFieldHandle FieldHandle
                {
                    get { throw new NotImplementedException(); }
                }

                public override Type FieldType
                {
                    get { throw new NotImplementedException(); }
                }

                public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, System.Globalization.CultureInfo culture)
                {
                    throw new NotImplementedException();
                }

                public override Type DeclaringType
                {
                    get { throw new NotImplementedException(); }
                }

                public override object[] GetCustomAttributes(Type attributeType, bool inherit)
                {
                    throw new NotImplementedException();
                }

                public override object[] GetCustomAttributes(bool inherit)
                {
                    throw new NotImplementedException();
                }

                public override bool IsDefined(Type attributeType, bool inherit)
                {
                    throw new NotImplementedException();
                }

                public override string Name
                {
                    get { throw new NotImplementedException(); }
                }

                public override Type ReflectedType
                {
                    get { throw new NotImplementedException(); }
                }

                #endregion
            }
        }
    }
}
